# -*- coding: utf-8 -*-
# @Time    : 2020/6/19 14:42
# @Author  : VillageTony
# @Email   : diaoyongcheng392@163.com
# @File    : library_book.py
# @Software: PyCharm
from odoo import models, fields, api
from odoo.addons import decimal_precision as dp
from odoo.exceptions import ValidationError
from datetime import timedelta
from odoo.exceptions import UserError
from odoo.tools.translate import _
import logging


class LibraryBook(models.Model):
    _name = 'library.book'
    _description = 'Library Book'

    # 首先对记录进行排序（按时间最近排序，然后按标题排序），添加如下代码：
    _order = 'date_release desc, name'

    # 添加如下代码来使用short_name字段作为记录的表示：
    _rec_name = 'short_name'
    short_name = fields.Char('简短书名', required=True)
    name = fields.Char('书名', required=True)
    author_ids = fields.Many2many('res.partner', string='作者')
    notes = fields.Text('备注')
    state = fields.Selection([('draft', '禁用'), ('available', '可用'), ('lost', '丢失'), ('borrowed', '借阅中')], '状态',
                             default='available')

    @api.onchange("name")
    def a(self):
        if not self.name:
            return
        # import re
        # if not re.findall("[0-9]{11,11}",self.name):
        #    raise ValidationError('bixushurushoujihao')
        self.short_name = self.name[0:1]

    # 要定义方法来修改所选图书的状态
    # 添加一个帮助方法来查看是否允许状态转换：
    @api.model
    def is_allowed_transition(self, old_state, new_state):
        '''
            目的是验证从一个状态到另一个状态的转换是否有效。在可允许列表中的元组即为可使用转换。
            例如，我们不想要允许lost到borrow的转换，因此没有加入(‘lost, ‘borrowed’)。
            '''
        allowed = [
            ('draft', 'available'),
            ('available', 'borrowed'),
            ('borrowed', 'available'),
            ('available', 'lost'),
            ('borrowed', 'lost'),
            ('lost', 'available')
        ]
        return (old_state, new_state) in allowed

    # 添加方法来修改一些书籍的状态为所传参数的新状态
    @api.model
    def change_state(self, new_state):
        for book in self:
            if book.is_allowed_transition(book.state, new_state):
                book.state = new_state
            else:
                msg = _('Move from %s to %s is not alowd') % (book.state, new_state)
                raise UserError(msg)

    # 添加方法通过调用change_state方法修改图书  视图中定义按钮 调用下列方法
    def make_available(self):
        self.change_state('available')

    def make_borrowed(self):
        self.change_state('borrowed')

    def make_lost(self):
        self.change_state('lost')

    description = fields.Html('描述')
    cover = fields.Binary('封面')
    out_of_print = fields.Boolean('已绝版?')
    date_release = fields.Date('出版日期')
    date_updated = fields.Datetime('最近更新')
    pages = fields.Integer('页数')
    reader_rating = fields.Float('读者平均评分', digits=(14, 4))
    cost_price = fields.Float('单价', dp.get_precision('Book Price'))
    retail_price = fields.Monetary('零售价')

    currency_id = fields.Many2one('res.currency', string='货币类型')
    '''图书        出版社
    一个出版社出版多本书，one2many
    多本图书有一个出版社出版  many2one
    publisher_id  在数据库层面是外键
    '''
    publisher_id = fields.Many2one('res.partner', string='出版社', ondelete='set null', context={}, domain=[])
    publisher_city = fields.Char('出版社城市', related='publisher_id.city')
    category_id = fields.Many2one('library.book.category')

    # 向模型添加约束验证
    _sql_constraints = [
        ('name_uniq',
         'UNIQUE (name)',
         'Book title must be unique.')
    ]

    @api.constrains('date_release')
    def _check_release_date(self):
        for record in self:
            if record.date_release and record.date_release > fields.Date.today():
                raise models.ValidationError('Release date must be in the past')

    age_days = fields.Float(
        string='Days Since Release',
        compute='_compute_age',
        inverse='_inverse_age',
        search='_search_age',
        store=False,  # optional
        compute_sudo=False  # optional
    )

    @api.depends('date_release')
    def _compute_age(self):
        today = fields.Date.today()
        for book in self.filtered('date_release'):
            delta = today - book.date_release
            book.age_days = delta.days

    def _inverse_age(self):
        today = fields.Date.today()
        for book in self.filtered('date_release'):
            d = today - timedelta(days=book.age_days)
            book.date_release = d

    def _search_age(self, operator, value):
        today = fields.Date.today()
        value_days = timedelta(days=value)
        value_date = today - value_days
        # convert the operator:
        # book with age > value have a date < value_date
        operator_map = {
            '>': '<', '>=': '<=',
            '<': '>', '<=': '>=',
        }
        new_op = operator_map.get(operator, operator)
        return [('date_release', new_op, value_date)]

    # 使用引用字段添加动态关联
    ref_doc_id = fields.Reference(
        selection='_referencable_models', string='Reference Document'
    )

    @api.model
    def _referencable_models(self):
        models = self.env['ir.model'].search([
            ('field_id.name', '=', 'message_ids')
        ])
        return [(x.model, x.name) for x in models]

    def find_book(self):
        domain = [
            '|',
            '&', ('name', 'like', 'Book Name'),
            ('category_id.name', 'ilike', 'Category Name'),
            '&', ('name', 'ilike', 'Booke Name 2'),
            ('category_id.name', 'ilike', 'Category Name 2')
        ]
        books = self.search(domain)

    # 执行原生SQL查询
    def average_book_occupation(self):
        sql_query = """
            SELECT
                lb.name,
                avg((EXTRACT(epoch from age(return_date, rent_date)) / 86400))::int
            FROM
                library_book_rent AS lbr
            JOIN
    l           ibrary_book as lb ON lb.id = lbr.book_id
            WHERE lbr.state = 'returned'
            GROUP BY lb.name;
        """
        self.env.cr.execute(sql_query)
        """
        fetchone()：从数据库返回一行，以元组进行封装（即便是仅查询了一个字段）。
        fetchall()：以元组列表从数据库中返回所有行。
        fetchalldict()：以列名对值的映射字典列表返回数据库中的所有行。
        """
        result = self.env.cr.fetchall()
        logger = logging()
        logger.info("Average book occupation: %s", result)


class ResPartner(models.Model):
    # _inherit属性用于继承已有模型
    _inherit = 'res.partner'
    published_book_ids = fields.One2many('library.book', 'publisher_id', string='Published Books')
    authored_book_ids = fields.Many2many('library.book', string='Authored Books')
    count_books = fields.Integer('NUmber of Authored Books', compute='_compute_count_books')

    @api.depends('authored_book_ids')
    def _compute_count_books(self):
        for r in self:
            r.count_books = len(r.authored_book_ids)


class LibraryBookRent(models.Model):
    _name = 'library.book.rent'

    book_id = fields.Many2one('library.book', 'Book', required=True)
    borrower_id = fields.Many2one('res.partner', 'Borrower',
                                  required=True)
    state = fields.Selection([('ongoing', 'Ongoing'),
                              ('returned', 'Returned')],
                             'State', default='ongoing',
                             required=True)
    rent_date = fields.Date(default=fields.Date.today)
    return_date = fields.Date()

